﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BibMan.model.database.bibtex;
using BibMan.model.database;
using BibMan.util;
using System.IO;
using System.Drawing.Drawing2D;
using BibMan.gui.util;

namespace BibMan.gui {
    public partial class ReferenceEditor : Form {
        public ReferenceEditor() {
            InitializeComponent();
            
            foreach (BibType bibType in Enum.GetValues(typeof(BibType))) {
                typeCombo.Items.Add(bibType.ToString());
            }
            typeCombo.AllowDrop = false;
            typeCombo.DropDownStyle = ComboBoxStyle.DropDownList;
            typeCombo.SelectedIndexChanged += typeSelectionChanged;
            
            this.pathButton.MouseClick += openFileClicked;

            delImage = Image.FromFile("C:\\Users\\ptay89\\Dropbox\\Visual Studio Projects\\BibRef\\BibRef\\Resources\\deleteicon.png");
            delImage = ImageUtil.ResizeImage(delImage, new Size(20, 20));
            addImage = Image.FromFile("C:\\Users\\ptay89\\Dropbox\\Visual Studio Projects\\BibRef\\BibRef\\Resources\\addicon.png");
            addImage = ImageUtil.ResizeImage(addImage, new Size(20, 20));
            this.button1.Image = addImage;
        }

        Image delImage;
        Image addImage;

        private List<String> extraQuestions = new List<String>();
        private Dictionary<String, int> questionInputLookup = new Dictionary<String, int>();
        private static readonly String TYPE_NAME = "Entry type";
        private ComboBox typeCombo = new ComboBox();
        private static readonly String ID_NAME = "Id";
        private TextBox idBox = new TextBox();
        private static readonly String PATH_NAME = "File path";
        private Button pathButton = new Button();
        private String path;
        private String Path {
            get { return path; }
            set { 
                path = value;
                if (path != null) {
                    int chars = Math.Min(30, path.Length);
                    this.pathButton.Text = String.Join(String.Empty, "..." + path.Substring(path.Length - chars, chars));
                } else {
                    this.pathButton.Text = "Open File";
                }
            }
        }

        private void PopulateQuestions(Reference r) {
            //to stop delay in refresing the list
            this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
            this.tableLayoutPanel1.Visible = false;

            questionInputLookup.Clear();
            this.tableLayoutPanel1.Controls.Clear();
            this.tableLayoutPanel1.RowCount = 0;
            
            idBox.Text = r.Id;
            AddQuestion(ID_NAME, idBox);
                       
            Path = r.Path;
            AddQuestion(PATH_NAME, pathButton, false);

            typeCombo.SelectedItem = r.BibItem.BibType.ToString();
            AddQuestion(TYPE_NAME, typeCombo);

            foreach (TagName tagName in BibItem.GetExpectedTags(r.BibItem.BibType)) {
                TextBox textBox = new TextBox();
                textBox.Text = r.BibItem[tagName];
                AddQuestion(tagName.ToString(), textBox);
            }
            foreach (String tagName in extraQuestions) {
                TextBox textBox = new TextBox();
                textBox.Text = r.BibItem[tagName];
                AddExtraQuestion(tagName, textBox);
            }
            
            this.tableLayoutPanel1.Visible = true;
            this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
        }

        private bool AddQuestion(String question, Control input, bool dontChangeControl = false) {
            if (this.tableLayoutPanel1.Controls.ContainsKey(question)) return false;
            input.TextChanged += answerInput;

            Label label = new Label();
            label.Text = question;
            label.Name = question + "Label";
            label.Dock = DockStyle.Fill;
            label.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
            this.tableLayoutPanel1.Controls.Add(label, 0, questionInputLookup.Count);

            input.Name = question;
            if (!dontChangeControl) {
                input.Width = 200;
            }
            this.tableLayoutPanel1.Controls.Add(input, 1, questionInputLookup.Count);

            questionInputLookup.Add(label.Text, tableLayoutPanel1.RowCount++);
            return true;
        }

        private bool AddExtraQuestion(String question, Control input, bool dontChangeControl = false) {
            if (questionInputLookup.ContainsKey(question)) {
                return false;
            }
            input.TextChanged += answerInput;

            LabelPanel label = new LabelPanel();
            label.Text = question;
            label.TextChanged += validateExtraQuestionName;
            label.Name = question + "Label";
            label.Dock = DockStyle.Fill;
            label.TextAlign = System.Drawing.ContentAlignment.MiddleRight;

            this.tableLayoutPanel1.Controls.Add(label, 0, questionInputLookup.Count);
            
            Button removeButton = new Button();
            removeButton.MouseClick += this.removeExtraContent;
            removeButton.AutoSize = true;
            removeButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            removeButton.Dock = DockStyle.Left;
            removeButton.Name = question;
            removeButton.Image = delImage;
            //this.tableLayoutPanel1.Controls.Add(removeButton, 0, questionCount);
            label.Controls.Add(removeButton);
            

            input.Name = question;
            if (!dontChangeControl) {
                input.Width = 200;
            }
            this.tableLayoutPanel1.Controls.Add(input, 1, questionInputLookup.Count);
            questionInputLookup.Add(label.Text, tableLayoutPanel1.RowCount++);
            return true;
        }

        private WriteOnce<Reference> original = new WriteOnce<Reference>();
        public Reference Original {
            get {
                return original.Value;
            }
            private set {
                if (!original.Assigned) original.Value = value;
                foreach (String tagName in original.Value.BibItem.ExtraTagNames) {
                    extraQuestions.Add(tagName);
                }
            }
        }
        private Reference reference;
        public Reference Reference {
            get {
                return reference;
            }
            set {
                this.reference = value.Clone() as Reference;
                if (Original == null) Original = value.Clone() as Reference;
            }
        }

        private void typeSelectionChanged(object sender, EventArgs e) {
            Reference.BibItem.BibType = getTypeFromCombo();
            PopulateQuestions(Reference);
        }

        private BibType getTypeFromCombo() {
            BibType tempType;
            if (Enum.TryParse<BibType>(typeCombo.SelectedItem.ToString(), out tempType)) {
                return tempType;
            } else {
                // Will never happen as combo box isn't editable.
                throw new InvalidOperationException("The BibItem type in the combo box was not valid");
            }
        }

        private void answerInput(object sender, EventArgs e) {
            String name = (sender as Control).Name;
            String value = (sender as Control).Text;
            if (name.Equals(TYPE_NAME)) {
                Reference.BibItem.BibType = getTypeFromCombo();
            } else if (name.Equals(ID_NAME)) {
                Reference.Id = value;
            } else if (name.Equals(PATH_NAME)) {
                Reference.Path = Path;
            } else {
                Reference.BibItem[name] = value;
            }
        }

        private void validateExtraQuestionName(object sender, String oldText, String newText) {
            //if (newText == oldText) return;
            LabelPanel label = sender as LabelPanel;
            label.TextChanged -= validateExtraQuestionName;
            //if the question was blank, set it to the old one
            if (newText.Equals(String.Empty)) {
                MessageBox.Show(this, "Blank tags names are not permitted.");
                //new item
                label.Text = oldText;
                if (newText.Equals(oldText)) {
                    RemoveQuestion(oldText);
                    return;
                }                
            } else if (questionInputLookup.ContainsKey(newText) && !questionInputLookup[oldText].Equals(questionInputLookup[newText])) {
                //if the question already exists, and its not this label that is that question, bad question
                MessageBox.Show(this, "This tag already exists.");
                label.Text = oldText;
            } else {
                //good question, update dictionary with new question
                int temp = questionInputLookup[oldText];
                questionInputLookup.Remove(oldText);
                questionInputLookup.Add(newText, temp);
                Reference.BibItem.AddTag(newText, Reference.BibItem[oldText]);
                Reference.BibItem.RemoveTag(oldText);
                extraQuestions.Remove(oldText);
                extraQuestions.Add(oldText);
            }
            label.TextChanged += validateExtraQuestionName;
        }

        private void addExtraContent(object sender, MouseEventArgs e) {
            String tagName = "Tag";
            for (int i=1; questionInputLookup.ContainsKey(tagName); i++) {
                tagName = String.Format("Tag{0}", i);
            }
            if (AddExtraQuestion(tagName, new TextBox())) {
                LabelPanel control = (LabelPanel)this.tableLayoutPanel1.GetControlFromPosition(0, questionInputLookup.Count - 1);
                extraQuestions.Add(tagName);
                control.BeginEdit();
            }
        }

        private void removeExtraContent(object sender, MouseEventArgs e) {
            Button but = sender as Button;
            RemoveQuestion(but.Name);
        }

        private void RemoveQuestion(String question) {
            Reference.BibItem.RemoveTag(question);
            extraQuestions.Remove(question);
            PopulateQuestions(Reference);
        }

        private void formShown(object sender, EventArgs e) {
            if (Original == null) Original = new Reference();
            PopulateQuestions(Original);
        }

        private void submitClicked(object sender, MouseEventArgs e) {
            if (idBox.Text.Equals(String.Empty)) {
                MessageBox.Show(this, "The reference does not have an Id", "Invalid reference");
            } else {
                this.DialogResult = DialogResult.OK;
            }
        }

        private void cancelClicked(object sender, MouseEventArgs e) {
            this.DialogResult = DialogResult.Cancel;
        }

        private void openFileClicked(object sender, MouseEventArgs e) {
            DialogResult result = this.browseDialog.ShowDialog(this);
            if (result.Equals(DialogResult.OK)) {
                this.Path = browseDialog.FileName;
            }
        }
    }
}
